﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace Gmantis.Controls
{
    [TypeConverter("CommandConverter")]
    public class Command : ICommand
    {
        // Fields
        private string _name;
        private Type _ownerType;

        // Events
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        // Methods
        public Command()
        {
            this._name = string.Empty;
            this._ownerType = null;
        }

        public Command(string name, Type ownerType)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (name.Length == 0)
            {
                throw new ArgumentException("StringEmpty", "name");
            }
            if (ownerType == null)
            {
                throw new ArgumentNullException("ownerType");
            }
            this._name = name;
            this._ownerType = ownerType;
        }

        public bool CanExecute(object parameter, UIElement target)
        {
            bool flag;
            return this.CriticalCanExecute(parameter, target, false, out flag);
        }

        private bool CanExecuteImpl(object parameter, UIElement target, bool trusted, out bool continueRouting)
        {
            if (target != null)
            {
                CanExecuteRoutedEventArgs args = new CanExecuteRoutedEventArgs(this, parameter)
                {
                    EventName = "PreviewCanExecuteEvent",
                    OriginalSource = target
                };
                this.CriticalCanExecuteWrapper(parameter, target, trusted, args);
                if (!args.Handled)
                {
                    args.EventName = "CanExecuteEvent";
                    this.CriticalCanExecuteWrapper(parameter, target, trusted, args);
                }
                continueRouting = args.ContinueRouting;
                return args.CanExecute;
            }
            continueRouting = false;
            return false;
        }

        internal bool CriticalCanExecute(object parameter, UIElement target, bool trusted, out bool continueRouting)
        {
            if (target == null)
            {
                target = FilterInputElement(FocusManager.GetFocusedElement());
            }
            return this.CanExecuteImpl(parameter, target, trusted, out continueRouting);
        }

        private void CriticalCanExecuteWrapper(object parameter, UIElement target, bool trusted, CanExecuteRoutedEventArgs args)
        {
            CommandManager.OnCanExecute(target, args);
        }

        public void Execute(object parameter, UIElement target)
        {
            if (target == null)
            {
                target = FilterInputElement(FocusManager.GetFocusedElement());
            }
            this.ExecuteImpl(parameter, target, null);
        }

        internal bool ExecuteCore(object parameter, UIElement target)
        {
            if (target == null)
            {
                target = FilterInputElement(FocusManager.GetFocusedElement());
            }
            return this.ExecuteImpl(parameter, target, null);
        }

        internal bool ExecuteImpl(object parameter, UIElement target, object originalSource)
        {
            if (target == null)
            {
                return false;
            }
            if (originalSource == null)
            {
                originalSource = target;
            }
            ExecutedRoutedEventArgs e = new ExecutedRoutedEventArgs(this, parameter)
            {
                EventName = "PreviewExecutedEvent",
                OriginalSource = originalSource
            };
            if (target != null)
            {
                CommandManager.OnExecuted(target, e);
                if (!e.Handled)
                {
                    e.EventName = "ExecutedEvent";
                    CommandManager.OnExecuted(target, e);
                }
            }
            return e.Handled;
        }

        private static UIElement FilterInputElement(object elem)
        {
            return (elem as UIElement);
        }

        bool ICommand.CanExecute(object parameter)
        {
            bool flag;
            return this.CanExecuteImpl(parameter, FilterInputElement(FocusManager.GetFocusedElement()), false, out flag);
        }

        void ICommand.Execute(object parameter)
        {
            this.Execute(parameter, FilterInputElement(FocusManager.GetFocusedElement()));
        }

        public override string ToString()
        {
            return this.Name;
        }

        // Properties
        public string Name
        {
            get
            {
                return this._name;
            }
        }

        public Type OwnerType
        {
            get
            {
                return this._ownerType;
            }
        }
    }
}
